// Filename: pgItem.I
// Created by:  drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University.  All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license.  You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////
//     Function: PGItem::set_name
//       Access: Public
//  Description:
////////////////////////////////////////////////////////////////////
INLINE void PGItem::
set_name(const string &name) {
  Namable::set_name(name);
  _lock.set_name(name);
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_region
//       Access: Public
//  Description: Returns the MouseWatcherRegion associated with this
//               item.  Every PGItem has a MouseWatcherRegion
//               associated with it, that is created when the PGItem
//               is created; it does not change during the lifetime of
//               the PGItem.  Even items that do not have a frame have
//               an associated MouseWatcherRegion, although it will
//               not be used in this case.
////////////////////////////////////////////////////////////////////
INLINE PGMouseWatcherRegion *PGItem:: 
get_region() const {
  LightReMutexHolder holder(_lock);
  return _region;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::set_notify
//       Access: Published
//  Description: Sets the object which will be notified when the
//               PGItem changes.  Set this to NULL to disable
//               this effect.  The PGItem does not retain
//               ownership of the pointer; it is your responsibility
//               to ensure that the notify object does not destruct.
////////////////////////////////////////////////////////////////////
INLINE void PGItem:: 
set_notify(PGItemNotify *notify) {
  LightReMutexHolder holder(_lock);
  if (_notify != (PGItemNotify *)NULL) {
    _notify->remove_item(this);
  }
  _notify = notify;
  if (_notify != (PGItemNotify *)NULL) {
    _notify->add_item(this);
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::has_notify
//       Access: Published
//  Description: Returns true if there is an object configured to be
//               notified when the PGItem changes, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool PGItem:: 
has_notify() const {
  LightReMutexHolder holder(_lock);
  return (_notify != (PGItemNotify *)NULL);
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_notify
//       Access: Published
//  Description: Returns the object which will be notified when the
//               PGItem changes, if any.  Returns NULL if there
//               is no such object configured.
////////////////////////////////////////////////////////////////////
INLINE PGItemNotify *PGItem:: 
get_notify() const {
  LightReMutexHolder holder(_lock);
  return _notify;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::set_frame
//       Access: Published
//  Description: Sets the bounding rectangle of the item, in local
//               coordinates.  This is the region on screen within
//               which the mouse will be considered to be within the
//               item.  Normally, it should correspond to the bounding
//               rectangle of the visible geometry of the item.
////////////////////////////////////////////////////////////////////
INLINE void PGItem::
set_frame(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) {
  set_frame(LVecBase4(left, right, bottom, top));
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::set_frame
//       Access: Published
//  Description: Sets the bounding rectangle of the item, in local
//               coordinates.  This is the region on screen within
//               which the mouse will be considered to be within the
//               item.  Normally, it should correspond to the bounding
//               rectangle of the visible geometry of the item.
////////////////////////////////////////////////////////////////////
INLINE void PGItem::
set_frame(const LVecBase4 &frame) {
  LightReMutexHolder holder(_lock);
  if (!_has_frame || _frame != frame) {
    _has_frame = true;
    _frame = frame;
    frame_changed();
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_frame
//       Access: Published
//  Description: Returns the bounding rectangle of the item.  See
//               set_frame().  It is an error to call this if
//               has_frame() returns false.
////////////////////////////////////////////////////////////////////
INLINE const LVecBase4 &PGItem::
get_frame() const {
  LightReMutexHolder holder(_lock);
  nassertr(has_frame(), _frame);
  return _frame;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::has_frame
//       Access: Published
//  Description: Returns true if the item has a bounding rectangle;
//               see set_frame().
////////////////////////////////////////////////////////////////////
INLINE bool PGItem::
has_frame() const {
  LightReMutexHolder holder(_lock);
  return _has_frame;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::clear_frame
//       Access: Published
//  Description: Removes the bounding rectangle from the item.  It
//               will no longer be possible to position the mouse
//               within the item; see set_frame().
////////////////////////////////////////////////////////////////////
INLINE void PGItem::
clear_frame() {
  LightReMutexHolder holder(_lock);
  if (_has_frame) {
    _has_frame = false;
    frame_changed();
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::set_state
//       Access: Published
//  Description: Sets the "state" of this particular PGItem.  
//
//               The PGItem node will render as if it were the
//               subgraph assigned to the corresponding index via
//               set_state_def().
////////////////////////////////////////////////////////////////////
INLINE void PGItem::
set_state(int state) {
  LightReMutexHolder holder(_lock);
  _state = state;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_state
//       Access: Published
//  Description: Returns the "state" of this particular PGItem.  See
//               set_state().
////////////////////////////////////////////////////////////////////
INLINE int PGItem::
get_state() const {
  LightReMutexHolder holder(_lock);
  return _state;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_active
//       Access: Published
//  Description: Returns whether the PGItem is currently active for
//               mouse events.  See set_active().
////////////////////////////////////////////////////////////////////
INLINE bool PGItem::
get_active() const {
  LightReMutexHolder holder(_lock);
  return (_flags & F_active) != 0;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_focus
//       Access: Published
//  Description: Returns whether the PGItem currently has focus for
//               keyboard events.  See set_focus().
////////////////////////////////////////////////////////////////////
INLINE bool PGItem::
get_focus() const {
  LightReMutexHolder holder(_lock);
  return (_flags & F_focus) != 0;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_background_focus
//       Access: Published
//  Description: Returns whether background_focus is currently
//               enabled.  See set_background_focus().
////////////////////////////////////////////////////////////////////
INLINE bool PGItem::
get_background_focus() const {
  LightReMutexHolder holder(_lock);
  return (_flags & F_background_focus) != 0;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::set_suppress_flags
//       Access: Published
//  Description: This is just an interface to set the suppress flags
//               on the underlying MouseWatcherRegion.  See
//               MouseWatcherRegion::set_suppress_flags().
////////////////////////////////////////////////////////////////////
INLINE void PGItem::
set_suppress_flags(int suppress_flags) {
  LightReMutexHolder holder(_lock);
  _region->set_suppress_flags(suppress_flags);
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_suppress_flags
//       Access: Published
//  Description: This is just an interface to get the suppress flags
//               on the underlying MouseWatcherRegion.  See
//               MouseWatcherRegion::get_suppress_flags().
////////////////////////////////////////////////////////////////////
INLINE int PGItem::
get_suppress_flags() const {
  LightReMutexHolder holder(_lock);
  return _region->get_suppress_flags();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_id
//       Access: Published
//  Description: Returns the unique ID assigned to this PGItem.  This
//               will be assigned to the region created with the
//               MouseWatcher, and will thus be used to generate event
//               names.
////////////////////////////////////////////////////////////////////
INLINE const string &PGItem::
get_id() const {
  LightReMutexHolder holder(_lock);
  return _region->get_name();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::set_id
//       Access: Published
//  Description: Set the unique ID assigned to this PGItem.  It is the
//               user's responsibility to ensure that this ID is
//               unique.
//
//               Normally, this should not need to be called, as the
//               PGItem will assign itself an ID when it is created,
//               but this function allows the user to decide to
//               redefine the ID to be something possibly more
//               meaningful.
////////////////////////////////////////////////////////////////////
INLINE void PGItem::
set_id(const string &id) {
  LightReMutexHolder holder(_lock);
  _region->set_name(id);
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_enter_prefix
//       Access: Published, Static
//  Description: Returns the prefix that is used to define the enter
//               event for all PGItems.  The enter event is the
//               concatenation of this string followed by get_id().
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_enter_prefix() {
  return "enter-";
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_exit_prefix
//       Access: Published, Static
//  Description: Returns the prefix that is used to define the exit
//               event for all PGItems.  The exit event is the
//               concatenation of this string followed by get_id().
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_exit_prefix() {
  return "exit-";
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_within_prefix
//       Access: Published, Static
//  Description: Returns the prefix that is used to define the within
//               event for all PGItems.  The within event is the
//               concatenation of this string followed by get_id().
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_within_prefix() {
  return "within-";
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_without_prefix
//       Access: Published, Static
//  Description: Returns the prefix that is used to define the without
//               event for all PGItems.  The without event is the
//               concatenation of this string followed by get_id().
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_without_prefix() {
  return "without-";
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_focus_in_prefix
//       Access: Published, Static
//  Description: Returns the prefix that is used to define the focus_in
//               event for all PGItems.  The focus_in event is the
//               concatenation of this string followed by get_id().
//
//               Unlike most item events, this event is thrown with no
//               parameters.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_focus_in_prefix() {
  return "fin-";
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_focus_out_prefix
//       Access: Published, Static
//  Description: Returns the prefix that is used to define the focus_out
//               event for all PGItems.  The focus_out event is the
//               concatenation of this string followed by get_id().
//
//               Unlike most item events, this event is thrown with no
//               parameters.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_focus_out_prefix() {
  return "fout-";
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_press_prefix
//       Access: Published, Static
//  Description: Returns the prefix that is used to define the press
//               event for all PGItems.  The press event is the
//               concatenation of this string followed by a button
//               name, followed by a hyphen and get_id().
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_press_prefix() {
  return "press-";
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_repeat_prefix
//       Access: Published, Static
//  Description: Returns the prefix that is used to define the repeat
//               event for all PGItems.  The repeat event is the
//               concatenation of this string followed by a button
//               name, followed by a hyphen and get_id().
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_repeat_prefix() {
  return "repeat-";
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_release_prefix
//       Access: Published, Static
//  Description: Returns the prefix that is used to define the release
//               event for all PGItems.  The release event is the
//               concatenation of this string followed by a button
//               name, followed by a hyphen and get_id().
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_release_prefix() {
  return "release-";
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_keystroke_prefix
//       Access: Published, Static
//  Description: Returns the prefix that is used to define the
//               keystroke event for all PGItems.  The keystroke event
//               is the concatenation of this string followed by a
//               hyphen and get_id().
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_keystroke_prefix() {
  return "keystroke-";
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_enter_event
//       Access: Published
//  Description: Returns the event name that will be thrown when the
//               item is active and the mouse enters its frame, but
//               not any nested frames.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_enter_event() const {
  LightReMutexHolder holder(_lock);
  return get_enter_prefix() + get_id();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_exit_event
//       Access: Published
//  Description: Returns the event name that will be thrown when the
//               item is active and the mouse exits its frame, or
//               enters a nested frame.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_exit_event() const {
  LightReMutexHolder holder(_lock);
  return get_exit_prefix() + get_id();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_within_event
//       Access: Published
//  Description: Returns the event name that will be thrown when the
//               item is active and the mouse moves within the
//               boundaries of the frame.  This is different from the
//               enter_event in that the mouse is considered within
//               the frame even if it is also within a nested frame.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_within_event() const {
  LightReMutexHolder holder(_lock);
  return get_within_prefix() + get_id();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_without_event
//       Access: Published
//  Description: Returns the event name that will be thrown when the
//               item is active and the mouse moves completely outside
//               the boundaries of the frame.  This is different from
//               the exit_event in that the mouse is considered
//               within the frame even if it is also within a nested
//               frame.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_without_event() const {
  LightReMutexHolder holder(_lock);
  return get_without_prefix() + get_id();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_focus_in_event
//       Access: Published
//  Description: Returns the event name that will be thrown when the
//               item gets the keyboard focus.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_focus_in_event() const {
  LightReMutexHolder holder(_lock);
  return get_focus_in_prefix() + get_id();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_focus_out_event
//       Access: Published
//  Description: Returns the event name that will be thrown when the
//               item loses the keyboard focus.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_focus_out_event() const {
  LightReMutexHolder holder(_lock);
  return get_focus_out_prefix() + get_id();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_press_event
//       Access: Published
//  Description: Returns the event name that will be thrown when the
//               item is active and the indicated mouse or keyboard
//               button is depressed while the mouse is within the
//               frame.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_press_event(const ButtonHandle &button) const {
  LightReMutexHolder holder(_lock);
  return get_press_prefix() + button.get_name() + "-" + get_id();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_repeat_event
//       Access: Published
//  Description: Returns the event name that will be thrown when the
//               item is active and the indicated mouse or keyboard
//               button is continuously held down while the mouse is
//               within the frame.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_repeat_event(const ButtonHandle &button) const {
  LightReMutexHolder holder(_lock);
  return get_repeat_prefix() + button.get_name() + "-" + get_id();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_release_event
//       Access: Published
//  Description: Returns the event name that will be thrown when the
//               item is active and the indicated mouse or keyboard
//               button, formerly clicked down is within the frame, is
//               released.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_release_event(const ButtonHandle &button) const {
  LightReMutexHolder holder(_lock);
  return get_release_prefix() + button.get_name() + "-" + get_id();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_keystroke_event
//       Access: Published
//  Description: Returns the event name that will be thrown when the
//               item is active and any key is pressed by the user.
////////////////////////////////////////////////////////////////////
INLINE string PGItem::
get_keystroke_event() const {
  LightReMutexHolder holder(_lock);
  return get_keystroke_prefix() + get_id();
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::set_text_node
//       Access: Published, Static
//  Description: Changes the TextNode object that will be used by all
//               PGItems to generate default labels given a string.
//               This can be loaded with the default font, etc.
////////////////////////////////////////////////////////////////////
INLINE void PGItem::
set_text_node(TextNode *node) {
  _text_node = node;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_focus_item
//       Access: Published, Static
//  Description: Returns the one PGItem in the world that currently
//               has keyboard focus, if any, or NULL if no item has
//               keyboard focus.  Use PGItem::set_focus() to activate
//               or deactivate keyboard focus on a particular item.
////////////////////////////////////////////////////////////////////
INLINE PGItem *PGItem::
get_focus_item() {
  return _focus_item;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::get_frame_inv_xform
//       Access: Published, Static
//  Description: Returns the inverse of the frame transform matrix
////////////////////////////////////////////////////////////////////
INLINE LMatrix4 PGItem::
get_frame_inv_xform() const {
  LightReMutexHolder holder(_lock);
  return _frame_inv_xform;
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::compute_area
//       Access: Private, Static
//  Description: Computes the area of the indicated frame.
////////////////////////////////////////////////////////////////////
INLINE PN_stdfloat PGItem::
compute_area(const LVecBase4 &frame) {
  return (frame[1] - frame[0]) * (frame[3] - frame[2]);
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::compare_largest
//       Access: Private, Static
//  Description: Given that largest is the pointer to the largest
//               frame so far, and largest_area is its area, compare
//               that to the area of the new frame; if the new frame
//               is larger, adjust largest and largest_area
//               appropriately.
////////////////////////////////////////////////////////////////////
INLINE void PGItem::
compare_largest(const LVecBase4 *&largest, PN_stdfloat &largest_area, 
                const LVecBase4 *new_frame) {
  PN_stdfloat new_area = compute_area(*new_frame);
  if (new_area > largest_area) {
    largest = new_frame;
    largest_area = new_area;
  }
}

////////////////////////////////////////////////////////////////////
//     Function: PGItem::StateDef::Constructor
//       Access: Public
//  Description: 
////////////////////////////////////////////////////////////////////
INLINE PGItem::StateDef::
StateDef() :
  _frame_stale(true)
{
}
